#include "stdafx.h"
#include "ScrollBar.h"
#include "WindowMetrics.h"
#include "TextMetrics.h"
#include "Text.h"
#include "Align.h"
#include <string>
using std::wstring;

void ScrollBar::UpdateScrollInfo()
{
	SCROLLINFO si;

	yMax=(text->GetNumberOfRows() + wm->GetWndHeight()/tm->GetLineHeight()/2)*tm->GetLineHeight();

	si.cbSize = sizeof(SCROLLINFO);
	si.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
	si.nMin = 0;
	si.nMax = yMax;
	si.nPage = (wm->GetWndHeight()/tm->GetLineHeight())*tm->GetLineHeight();

	if (si.nMax < (int)si.nPage) {
		yPos = 0;
		InvalidateRect(hWnd, NULL, FALSE);
	}
	si.nPos=yPos;
	SetScrollInfo(hWnd, SB_VERT, &si, TRUE);

	if (text->GetAlignStyle() == NO_ALIGN) 
	{
		int MaxLength = 0;
		for (int i = 0; i < text->GetNumberOfRows(); i++) 
		{
			MaxLength = max(MaxLength,int(text->GetString(i).size()));
		}

		xMax = int(MaxLength*tm->GetFontWidthAverage()*2);
		si.nMax = xMax;
		si.nPage = wm->GetFormattingWidth();
		si.nPos = xPos;
		SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
	}
}

void ScrollBar::OnHScroll(UINT code)
{
	int xInc = 0;
	SCROLLINFO si;

	switch(code)
	{
	case SB_LINEUP:
		xInc = -tm->GetFontHeight();
		break;
	case SB_LINEDOWN:
		xInc = tm->GetFontHeight();
		break;
	case SB_PAGEUP:
		xInc = -wm->GetWndHeight();
		break;
	case SB_PAGEDOWN:
		xInc = wm->GetWndHeight();
		break;
	case SB_THUMBTRACK:
		si.cbSize = sizeof(SCROLLINFO);
		si.fMask = SIF_TRACKPOS;
		GetScrollInfo(hWnd, SB_HORZ, &si);
		xInc = si.nTrackPos - xPos;
		break;
	default:
		break;
	}

	xInc = max(-xPos, min(xInc, xMax - xPos));
	xPos = xPos + xInc;
	RECT formattingRect = wm->GetFormattingRect();
	ScrollWindow(hWnd, -xInc, 0, NULL, &formattingRect);
	SetScrollPos(hWnd, SB_HORZ, xPos, TRUE);

	POINT pt;
	GetCaretPos(&pt);
	if(pt.x < wm->GetMarginWidth())
	{
		if(!hide_caret)
		{
			HideCaret(hWnd);
			hide_caret = true;
		}
	}
	else
	{
		ShowCaret(hWnd);
		hide_caret = false;
	}
}

void ScrollBar::OnVScroll(UINT code)
{
	int yInc = 0;
	SCROLLINFO si;
	int LinePerPage = wm->GetWndHeight() / tm->GetLineHeight() * tm->GetLineHeight();

	switch(code)
	{
	case SB_LINEUP:
		yInc = -tm->GetLineHeight();
		break;
	case SB_LINEDOWN:
		yInc = tm->GetLineHeight();
		break;
	case SB_PAGEUP:
		yInc = -LinePerPage;
		break;
	case SB_PAGEDOWN:
		yInc = LinePerPage;
		break;
	case SB_THUMBTRACK:
		si.cbSize = sizeof(SCROLLINFO);
		si.fMask = SIF_TRACKPOS;
		GetScrollInfo(hWnd, SB_VERT, &si);
		yInc = si.nTrackPos - yPos;
		break;
	default:
		break;
	}
	yInc = max(-yPos, min(yInc, yMax - yPos - LinePerPage));
	yInc = yInc - (yInc % tm->GetLineHeight());
	yPos = yPos + yInc;
	ScrollWindow(hWnd, 0, -yInc, NULL, NULL);
	SetScrollPos(hWnd, SB_VERT, yPos, TRUE);
}

void ScrollBar::SetHScroll()
{
	DWORD dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
	dwStyle |= WS_HSCROLL;
	RedrawNonClientArea(dwStyle);
}

void ScrollBar::SetVScroll()
{
	DWORD dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
	dwStyle |= WS_VSCROLL;
	RedrawNonClientArea(dwStyle);
}

void ScrollBar::RemoveHScroll()
{
	DWORD dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
	dwStyle &= ~WS_HSCROLL;
	RedrawNonClientArea(dwStyle);
}

void ScrollBar::RemoveVScroll()
{
	DWORD dwStyle = GetWindowLongPtr(hWnd, GWL_STYLE);
	dwStyle &= ~WS_HSCROLL;
	RedrawNonClientArea(dwStyle);
}

int ScrollBar::GetXPos()
{
	return xPos;
}

int ScrollBar::GetYPos()
{
	return yPos;
}

void ScrollBar::SetXPos(int x)
{
	xPos = x;
}

void ScrollBar::SetYPos(int y)
{
	yPos = y;
}

int ScrollBar::GetYMax()
{
	return yMax;
}

ScrollBar::ScrollBar(void)
{
	hide_caret = false;
	xPos = yPos = 0;
}

ScrollBar::~ScrollBar(void)
{
}

void ScrollBar::Init(HWND hWnd, WindowMetrics* wm, Text* text, TextMetrics* tm)
{
	this->hWnd = hWnd;
	this->wm = wm;
	this->text = text;
	this->tm = tm;
}

void ScrollBar::RedrawNonClientArea(DWORD dwStyle)
{
	SetWindowLongPtr(hWnd,GWL_STYLE,dwStyle);
	SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,
		SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
}